package com.kingmed.kmss.admin.modules.ums.service.impl;

import com.alibaba.excel.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kingmed.kmss.admin.config.CustomConfig;
import com.kingmed.kmss.admin.modules.ums.mapper.UmsBpmnMembershipMapper;
import com.kingmed.kmss.admin.modules.ums.model.UmsBpmnGroup;
import com.kingmed.kmss.admin.modules.ums.model.UmsBpmnMembership;
import com.kingmed.kmss.admin.modules.ums.model.UmsOrganization;
import com.kingmed.kmss.admin.modules.ums.service.UmsAdminService;
import com.kingmed.kmss.admin.modules.ums.service.UmsBpmnGroupService;
import com.kingmed.kmss.admin.modules.ums.service.UmsBpmnMembershipService;
import com.kingmed.kmss.admin.modules.ums.service.UmsOrganizationService;
import com.kingmed.kmss.common.bo.bpmn.GroupBO;
import com.kingmed.kmss.common.bo.bpmn.UserBO;
import com.kingmed.kmss.common.bo.bpmn.UserGroupBO;
import com.kingmed.kmss.common.dto.admin.ums.BpmnGroupDTO;
import com.kingmed.kmss.common.dto.admin.ums.BpmnMembershipDTO;
import com.kingmed.kmss.common.dto.admin.ums.BpmnQueryDTO;
import com.kingmed.kmss.common.dto.admin.ums.OrganizationTileDTO;
import com.kingmed.kmss.common.utils.BeanCopyUtils;
import com.kingmed.kmss.framework.feign.client.bpmn.RemoteBpmnGroupService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 后台流程角色与用户关联表 服务实现类
 * </p>
 *
 * @author wyl
 * @since 2023-02-17
 */
@Slf4j
@Service
public class UmsBpmnMembershipServiceImpl extends ServiceImpl<UmsBpmnMembershipMapper, UmsBpmnMembership> implements UmsBpmnMembershipService {

    @Autowired
    private RemoteBpmnGroupService remoteBpmnGroupService;
    @Autowired
    private UmsAdminService umsAdminService;
    @Autowired
    private UmsOrganizationService umsOrganizationService;
    @Autowired
    private UmsBpmnGroupService groupService;
    @Autowired
    private CustomConfig customConfig;

    @Transactional
    @Override
    public int update(List<BpmnMembershipDTO> reqDto) {
        List<UmsBpmnMembership> entityList = BeanCopyUtils.copyList(reqDto, UmsBpmnMembership.class);
        if (entityList == null) return 0;

        List<UmsBpmnMembership> newEntityList = new ArrayList<>();
        entityList.forEach(entity -> {
            if (dataNotExist(entity)) {
                this.setAdminBranchRegion(entity);
                entity.setGroupKey(this.getGroupKey(entity.getGroupId()));
                newEntityList.add(entity);

            }
        });
        this.saveOrUpdateBatch(newEntityList);

        this.bpmnAssignUserToGroups(newEntityList);

        return reqDto.size();
    }

    private String getGroupKey(Long groupId) {
        UmsBpmnGroup group = groupService.getById(groupId);
        return group.getGroupKey();
    }

    private void setAdminBranchRegion(UmsBpmnMembership entity) {
        List<UmsOrganization> adminOrgList = umsAdminService.getOrgList(entity.getAdminId());
        if (CollectionUtils.isNotEmpty(adminOrgList)) {
            OrganizationTileDTO tileDTO = umsOrganizationService.getOrgGroupRegionBranchByOrgId(adminOrgList.get(0).getId());
            if (tileDTO != null) {
                entity.setAdminBranchId(tileDTO.getSubCompanyId());
                entity.setAdminRegionId(tileDTO.getRegionId());
            }
        }
    }

    private boolean dataNotExist(UmsBpmnMembership entity) {
        List<UmsBpmnMembership> list = this.list(new QueryWrapper<UmsBpmnMembership>().lambda()
                .eq(UmsBpmnMembership::getAdminId, entity.getAdminId())
                .eq(UmsBpmnMembership::getGroupId, entity.getGroupId())
                .ne(entity.getId() != null, UmsBpmnMembership::getId, entity.getId())
        );
        return CollectionUtils.isEmpty(list);
    }

    private void bpmnAssignUserToGroups(List<UmsBpmnMembership> newEntityList) {
        Map<String, List<UmsBpmnMembership>> dtoMap = newEntityList.stream().collect(Collectors.groupingBy(UmsBpmnMembership::getUsername));
        dtoMap.forEach((username, list) -> {
            UserBO userBo = new UserBO();
            userBo.setUserId(username);
            userBo.setGroups(this.toGroupDtoList(list));
            remoteBpmnGroupService.assignUserToGroups(userBo);
        });
    }

    private List<GroupBO> toGroupDtoList(List<UmsBpmnMembership> newEntityList) {
        List<GroupBO> list = new ArrayList<>();
        newEntityList.forEach(dto -> {
            GroupBO groupBO = new GroupBO();
            groupBO.setGroupId(dto.getGroupKey());
            list.add(groupBO);
        });
        return list;
    }

    @Transactional
    @Override
    public int delete(List<Long> idList) {
        List<UmsBpmnMembership> entityList = this.listByIds(idList);

        this.getBaseMapper().deleteBatchIds(idList);

        for (UmsBpmnMembership entity : entityList) {
            this.bpmnUnAssignUserToGroups(entity);
        }

        return idList.size();
    }

    @Transactional
    @Override
    public int deleteByGroupId(List<Long> groupIdList) {
        LambdaQueryWrapper<UmsBpmnMembership> wrapper = new QueryWrapper<UmsBpmnMembership>().lambda().in(UmsBpmnMembership::getGroupId, groupIdList);

        List<UmsBpmnMembership> entityList = this.list(wrapper);

        int deleteCnt = this.getBaseMapper().delete(wrapper);

        for (UmsBpmnMembership entity : entityList) {
            this.bpmnUnAssignUserToGroups(entity);
        }

        return deleteCnt;
    }

    private void bpmnUnAssignUserToGroups(UmsBpmnMembership entity) {
        UserGroupBO userGroupBo = new UserGroupBO();
        userGroupBo.setGroupId(entity.getGroupKey());
        userGroupBo.setUserId(entity.getUsername());
        remoteBpmnGroupService.unassignUserFromGroups(userGroupBo);
    }

    @Override
    public Page<BpmnMembershipDTO> pageList(BpmnQueryDTO queryDTO) {
        Page<UmsBpmnMembership> page = new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize());
        LambdaQueryWrapper<UmsBpmnMembership> wrapper = new QueryWrapper<UmsBpmnMembership>().lambda()
                .eq(queryDTO.getGroupId() != null, UmsBpmnMembership::getGroupId, queryDTO.getGroupId())
                .eq(queryDTO.getAdminId() != null, UmsBpmnMembership::getAdminId, queryDTO.getAdminId());
        page = this.page(page, wrapper);
        return this.toDtoPage(page);
    }

    private Page<BpmnMembershipDTO> toDtoPage(Page<UmsBpmnMembership> resultPage) {
        Page<BpmnMembershipDTO> dtoPage = new Page<>(resultPage.getCurrent(), resultPage.getSize(), resultPage.getTotal(), resultPage.searchCount());
        if (CollectionUtils.isEmpty(resultPage.getRecords())) {
            return dtoPage;
        }
        dtoPage.setRecords(BeanCopyUtils.copyList(resultPage.getRecords(), BpmnMembershipDTO.class));
        return dtoPage;
    }

    @Override
    public List<BpmnMembershipDTO> queryList(BpmnQueryDTO queryDTO) {
        return this.getBaseMapper().queryList(queryDTO);
    }


    @Override
    public List<BpmnGroupDTO> listByParam(BpmnQueryDTO queryDTO) {
        List<BpmnGroupDTO> dtoList = this.getBaseMapper().listByParam(queryDTO);
        if (CollectionUtils.isNotEmpty(dtoList)) {
            for (BpmnGroupDTO dto : dtoList) {
                dto.setAdminList(this.getBaseMapper().listAdminInGroup(dto.getId()));
            }
        }
        return dtoList;
    }

    @Override
    public List<BpmnGroupDTO> listByAdminId(Long adminId, String username) {
        BpmnQueryDTO queryDTO = new BpmnQueryDTO();
        queryDTO.setAdminId(adminId);
        queryDTO.setUsername(username);
        return this.getBaseMapper().listByParam(queryDTO);
    }

    @Override
    public List<BpmnMembershipDTO> listAdminInGroup(Long groupId) {
        List<BpmnMembershipDTO> dtoList = this.getBaseMapper().adminInGroup(groupId);
        if (CollectionUtils.isNotEmpty(dtoList)) {
            for (BpmnMembershipDTO dto : dtoList) {
                // 一个用户只有一个组织
                List<UmsOrganization> orgList = umsAdminService.getOrgList(dto.getAdminId());
                if (CollectionUtils.isNotEmpty(orgList)) {
                    dto.setOrgFullName(umsOrganizationService.getAdminOrgFullName(orgList.get(0).getId()));
                }
            }
        }
        return dtoList;
    }

    @Transactional
    @Override
    public int adminGroupSave(List<BpmnMembershipDTO> reqDto) {
        //先删
        List<UmsBpmnMembership> entityList = this.list(
                new QueryWrapper<UmsBpmnMembership>().lambda().eq(UmsBpmnMembership::getAdminId, reqDto.get(0).getAdminId()));
        List<Long> shipIdList = entityList.stream().map(UmsBpmnMembership::getId).collect(Collectors.toList());

        if (CollectionUtils.isNotEmpty(shipIdList)) {
            this.getBaseMapper().deleteBatchIds(shipIdList);
        }

        //如果入参size=1，且group id为空，表明前端已经把审批角色删光，不需要update
        if (CollectionUtils.isNotEmpty(reqDto) && reqDto.get(0).getGroupId() != null) {
            this.update(reqDto);
        }
        return reqDto.size();
    }

    @Override
    public void updateBranchRegion(Long adminId) {
        // 配置了忽略同步的人，不更新其子公司信息
        List<String> usernameList = this.getIgnoreSyncMembership();
        log.debug("更新用户id【{}】, 忽略配置:{}", adminId, usernameList);
        List<UmsBpmnMembership> entityList = this.list(new QueryWrapper<UmsBpmnMembership>().lambda()
                .eq(UmsBpmnMembership::getAdminId, adminId)
                .notIn(CollectionUtils.isNotEmpty(usernameList), UmsBpmnMembership::getUsername, usernameList)
        );
        // 更新子公司信息
        if (CollectionUtils.isNotEmpty(entityList)) {
            entityList.forEach(this::setAdminBranchRegion);
            this.saveOrUpdateBatch(entityList);
        }
    }

    private List<String> getIgnoreSyncMembership() {
        String ignoreSyncMembership = customConfig.getIgnoreSyncMembership();
        if (StringUtils.isBlank(ignoreSyncMembership)) {
            return Collections.emptyList();
        }
        String[] usernameArr = ignoreSyncMembership.split(",");
        return Arrays.asList(usernameArr);
    }
}
